Skip to content

fix(head): avoid CSP warnings when disabled#2084

Merged
ascorbic merged 2 commits into
emdash-cms:mainfrom
logelog:fix/head-csp-warning
Jul 17, 2026
Merged

fix(head): avoid CSP warnings when disabled#2084
ascorbic merged 2 commits into
emdash-cms:mainfrom
logelog:fix/head-csp-warning

Conversation

@logelog

@logelog logelog commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Avoids Astro CSP warnings from EmDashHead when a host project has not enabled Astro's built-in CSP support.

This is a follow-up to #1695. The JSON-LD integration currently reads Astro.csp before it knows whether CSP is enabled. Astro 7 warns on every affected production render even when the page does not need CSP handling.

The fix:

  • records the normalized CSP-enabled state in EmDash's virtual config;
  • keeps access to Astro.csp lazy when CSP is disabled;
  • preserves JSON-LD script hash registration when CSP is enabled;
  • adds regression coverage for both paths.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore

Checklist

  • I have read CONTRIBUTING.md
  • pnpm --filter emdash typecheck passes
  • Changed-file type-aware lint passes
  • Targeted tests pass
  • pnpm format:check passes
  • I added regression coverage
  • No user-visible admin strings were added
  • I added a changeset
  • New features link to an approved Discussion (not applicable; bug fix)

Validation

  • pnpm --filter emdash exec vitest run tests/unit/plugins/page-metadata.test.ts - 33 tests passed
  • pnpm --filter emdash typecheck
  • changed-file type-aware oxlint
  • pnpm format:check
  • git diff --check
  • production SSR reproduction with the simple demo:
    • current main: request returns 200 and logs context.csp was used ... but CSP was not configured
    • this branch: request returns 200 with no CSP warning

@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 28628ee

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@logelog
logelog marked this pull request as ready for review July 16, 2026 22:13
@github-actions github-actions Bot added the review/needs-review No maintainer or bot review yet label Jul 16, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right fix for the right problem. Capturing the CSP-enabled state in the virtual config and keeping Astro.csp behind a lazy getter avoids Astro’s warning on non-CSP sites while preserving JSON-LD script-hash registration for sites that do enable CSP. The change is additive, narrowly scoped, and fits EmDash’s existing virtual-config architecture.

What I checked:

  • Diff and full changed files (EmDashHead.astro, page/metadata.ts, astro/integration/index.ts, virtual-modules.d.ts, tests, changeset).
  • Virtual-module serialization path (serializableConfiggenerateConfigModule).
  • All Astro.csp / insertScriptHash / security.csp usage sites in the repo.
  • AGENTS.md conventions (changeset, imports, tests).

Headline: implementation is correct, but the new regression test asserts a side-effect order that Promise.all does not guarantee, which is likely to flake. I also noted an optional import-convention alignment.

Comment on lines +339 to +342
expect(getCsp).toHaveBeenCalledOnce();
expect(insertScriptHash).toHaveBeenCalledTimes(2);
expect(insertScriptHash).toHaveBeenNthCalledWith(1, await createSha256CspHash(scripts[0].json));
expect(insertScriptHash).toHaveBeenNthCalledWith(2, await createSha256CspHash(scripts[1].json));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[needs fixing] registerJsonLdCspHashes registers hashes with await Promise.all(scripts.map(async …)), so the two async crypto.subtle.digest calls run concurrently. The order in which their insertScriptHash side effects execute is not guaranteed by Promise.all, making the toHaveBeenNthCalledWith(1, …) / toHaveBeenNthCalledWith(2, …) assertions potentially flaky. Since CSP hash order has no functional significance, assert set membership instead of order.

Suggested change
expect(getCsp).toHaveBeenCalledOnce();
expect(insertScriptHash).toHaveBeenCalledTimes(2);
expect(insertScriptHash).toHaveBeenNthCalledWith(1, await createSha256CspHash(scripts[0].json));
expect(insertScriptHash).toHaveBeenNthCalledWith(2, await createSha256CspHash(scripts[1].json));
const hash0 = await createSha256CspHash(scripts[0].json);
const hash1 = await createSha256CspHash(scripts[1].json);
expect(getCsp).toHaveBeenCalledOnce();
expect(insertScriptHash).toHaveBeenCalledTimes(2);
expect(insertScriptHash).toHaveBeenCalledWith(hash0);
expect(insertScriptHash).toHaveBeenCalledWith(hash1);

* ```
*/
import type { PublicPageContext, PageMetadataContribution } from "../plugins/types.js";
import virtualConfig from "virtual:emdash/config";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] AGENTS.md’s Imports convention asks for a // @ts-ignore - virtual module comment above imports from virtual:emdash/config. Other files in the repo follow this pattern. Consider adding the comment for consistency, especially since .astro components are excluded from the core tsconfig.json.

Suggested change
import virtualConfig from "virtual:emdash/config";
// @ts-ignore - virtual module
import virtualConfig from "virtual:emdash/config";

@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/needs-review No maintainer or bot review yet labels Jul 17, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/admin@2084

@emdash-cms/auth

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth@2084

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/auth-atproto@2084

@emdash-cms/blocks

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/blocks@2084

@emdash-cms/cloudflare

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/cloudflare@2084

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/contentful-to-portable-text@2084

emdash

npm i https://pkg.pr.new/emdash-cms/emdash@2084

create-emdash

npm i https://pkg.pr.new/emdash-cms/emdash/create-emdash@2084

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/gutenberg-to-portable-text@2084

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-cli@2084

@emdash-cms/plugin-types

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-types@2084

@emdash-cms/registry-client

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-client@2084

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-lexicons@2084

@emdash-cms/registry-verification

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/registry-verification@2084

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/sandbox-workerd@2084

@emdash-cms/x402

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/x402@2084

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-ai-moderation@2084

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-atproto@2084

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-audit-log@2084

@emdash-cms/plugin-color

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-color@2084

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-embeds@2084

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-field-kit@2084

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-forms@2084

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/emdash-cms/emdash/@emdash-cms/plugin-webhook-notifier@2084

commit: 28628ee

@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Jul 17, 2026

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of #2084: CSP warning fix

This is the follow-up to the first review of the same PR. My earlier concern was that the new regression test asserted a Promise.all-side-effect order that the runtime does not guarantee, making it likely to flake. That has been addressed.

What I checked

  • Diff and full changed files (EmDashHead.astro, page/metadata.ts, astro/integration/index.ts, virtual-modules.d.ts, the regression tests, and the changeset).
  • Virtual-module serialization path (serializableConfiggenerateConfigModule).
  • All Astro.csp / insertScriptHash / security.csp usage sites in the repo to confirm this is the only affected component.
  • AGENTS.md conventions: changeset, virtual-module // @ts-ignore, .js extensions on internal imports, test coverage, no user-facing admin strings.

Approach

The fix is still the right one for the right problem: capture the CSP-enabled state at build/integration setup time, serialize it through the existing virtual config, and keep Astro.csp access behind a lazy getter so non-CSP sites never trigger Astro's warning. The change is additive, narrowly scoped, and fits EmDash's virtual-config architecture.

Status of prior finding

  • Test flakiness resolved. The enabled-path test now independently computes the expected SHA-256 hashes and uses order-insensitive toHaveBeenCalledWith assertions, so it no longer relies on the insertion order produced by Promise.all.
  • Import conventions in the changed files align with AGENTS.md (// @ts-ignore - virtual module, .js extensions on internal imports, no extension on package imports).

Headline

Implementation is correct, regression coverage is present and now order-safe, and I see no remaining issues. LGTM.

@emdashbot emdashbot Bot removed the bot:review Trigger an emdashbot code review on this PR label Jul 17, 2026

@ascorbic ascorbic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@ascorbic
ascorbic merged commit d303738 into emdash-cms:main Jul 17, 2026
48 checks passed
@emdashbot emdashbot Bot mentioned this pull request Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core cla: signed review/needs-rereview Author pushed changes since the last review size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants